/**
 * @file    bt_rs485.c
 * @author  chenwenrui
 * @brief   485 提供发送、接收数据回调接口
 * @version V1.0
 * @date 2023-09-27
 * @copyright Copyright (c) 2022
 *
 * 系统资源：
 *      GPIO:
 *          P54-485使能
 *      UART2:
 *          P10&P11
 *
 *
 */

#include "GPIO.h"
#include "UART.h"
#include "delay.h"
#include "bt_rs485.h"

#define BT_RS485_EN P54
#define BT_RS485_BUFFER_SIZE COM_RX2_Lenth

typedef struct
{
    unsigned char rs485_rx_r_cnt;                        // 串口接收buf，读计数
    unsigned char rs485_rx_w_cnt;                        // 串口接收buf，写计数
    unsigned char rs485_rx_buffer[BT_RS485_BUFFER_SIZE]; // 本地串口接收缓存

    unsigned char rs485_tx_buffer[BT_RS485_BUFFER_SIZE]; // 本地串口发送缓存
    unsigned char rs485_msg[9];
    unsigned char rs485_msg_cnt; // 485协议解析计数

} rs485_manager_s;

static rs485_manager_s xdata g_rs485_manager = {0};

/**
 * @brief  RS485 使能切换延时
 * @note
 * @retval
 */
static void wait_rs485(void)
{
#if 1
    delay_ms(3);
#else
    int i = 39;
    while (i--)
    {
        Delay(500);
    }
#endif
}

/**
 * @brief  RS485数据发送
 * @param  buf：缓存区数据
 * @param  len:数据长度
 * @note
 * @retval
 */
void bt_rs485_send_datas(unsigned char *buf, unsigned char len)
{
    unsigned char data i;
    wait_rs485();
    for (i = 0; i < len; i++)
        TX2_write2buff(buf[i]); // 写入发送缓冲，指针+1
}
/**
 * @brief  RS485数据校验
 * @param  buf：缓存区数据
 * @param  len:数据长度
 * @note
 * @retval
 */
unsigned char bt_rs485_check_xor(unsigned char *buf, unsigned char len)
{
    unsigned char data d = 0;
    while (len-- > 0)
        d ^= *buf++;
    return d;
}
void bt_rs485_reset(void)
{
    while (COM2.RX_Cnt != g_rs485_manager.rs485_rx_r_cnt)
    {
        g_rs485_manager.rs485_rx_r_cnt = (g_rs485_manager.rs485_rx_r_cnt + 1) % COM_RX2_Lenth; // BT_RS485_BUFFER_SIZE;
        // delay_ms(30);
    }
    g_rs485_manager.rs485_msg_cnt = 0;

    // COM2.RX_Cnt = 0;
    // g_rs485_manager.rs485_rx_r_cnt = 0;
}
/**
 * @brief  BT 485协议处理框架，从串口缓冲区读取数据解析，详细参考《北泰智能485协议》
 * @param  bt_rs485_parser ，485协议初次匹配，接收到9字节回调解析函数
 * @note   需要尽快实时解析，防止数据丢失
 * @retval None
 */
void bt_rs485_loop()
{
    unsigned char tmp;

    // 串口中断接收数据，从缓存区读取到本地进行解析
    while (COM2.RX_Cnt != g_rs485_manager.rs485_rx_r_cnt)
    {
        tmp = RX2_Buffer[g_rs485_manager.rs485_rx_r_cnt];
        g_rs485_manager.rs485_rx_r_cnt = (g_rs485_manager.rs485_rx_r_cnt + 1) % BT_RS485_BUFFER_SIZE;
        switch (g_rs485_manager.rs485_msg_cnt)
        {
        case 0: // 匹配协议头部
            if (tmp == 0xaa)
            {
                g_rs485_manager.rs485_msg[g_rs485_manager.rs485_msg_cnt] = tmp;
                g_rs485_manager.rs485_msg_cnt++;
            }
            else
            {
                g_rs485_manager.rs485_msg_cnt = 0;
            }
            break;
        case 1: // 匹配协议头部
            if (tmp == 0xaa)
            {
                g_rs485_manager.rs485_msg[g_rs485_manager.rs485_msg_cnt] = tmp;
                g_rs485_manager.rs485_msg_cnt++;
            }
            else
            {
                g_rs485_manager.rs485_msg_cnt = 0;
            }
            break;

        case 8: // 接收到足够数据进行下一步解析
            g_rs485_manager.rs485_msg[g_rs485_manager.rs485_msg_cnt] = tmp;
            rs485_parser(g_rs485_manager.rs485_msg, 9);
            g_rs485_manager.rs485_msg_cnt = 0;
            break;
        default:
            g_rs485_manager.rs485_msg[g_rs485_manager.rs485_msg_cnt] = tmp;
            g_rs485_manager.rs485_msg_cnt++;
            break;
        }
    }
}

/**
 * @brief RS485 初始化
 * @note
 * @retval
 */
void bt_rs485_init(void)
{
    GPIO_InitTypeDef xdata GPIO_InitStructure;        // 结构定义
    COMx_InitDefine xdata COMx_InitStructure;         // 结构定义
                                                      // uart 2
    GPIO_InitStructure.Pin = GPIO_Pin_0 | GPIO_Pin_1; // 指定要初始化的IO, GPIO_Pin_0 ~ GPIO_Pin_7
    GPIO_InitStructure.Mode = GPIO_PullUp;            // 指定IO的输入或输出方式,GPIO_PullUp,GPIO_HighZ,GPIO_OUT_OD,GPIO_OUT_PP
    GPIO_Inilize(GPIO_P1, &GPIO_InitStructure);       // 初始化

    // 485使能管脚初始化
	GPIO_InitStructure.Pin = GPIO_Pin_4;		//指定要初始化的IO, GPIO_Pin_0 ~ GPIO_Pin_7
	GPIO_InitStructure.Mode = GPIO_OUT_PP;		//指定IO的输入或输出方式,GPIO_PullUp,GPIO_HighZ,GPIO_OUT_OD,GPIO_OUT_PP
	GPIO_Inilize(GPIO_P5, &GPIO_InitStructure); //初始化

    // RS485串口配置
    COMx_InitStructure.UART_Mode = UART_8bit_BRTx;   // 模式,   UART_ShiftRight,UART_8bit_BRTx,UART_9bit,UART_9bit_BRTx
    COMx_InitStructure.UART_BRT_Use = BRT_Timer2;    // 使用波特率, BRT_Timer1, BRT_Timer2 (注意: 串口2固定使用BRT_Timer2)
    COMx_InitStructure.UART_BaudRate = 115200ul;     // 波特率,     110 ~ 115200
    COMx_InitStructure.UART_RxEnable = ENABLE;       // 接收允许,   ENABLE或DISABLE
    COMx_InitStructure.UART_Interrupt = ENABLE;      // 中断允许,   ENABLE或DISABLE
    COMx_InitStructure.UART_Polity = Polity_1;       // 指定中断优先级(低到高) Polity_0,Polity_1,Polity_2,Polity_3
    COMx_InitStructure.UART_P_SW = UART2_SW_P10_P11; // 切换端口,   UART2_SW_P10_P11,UART2_SW_P46_P47
    UART_Configuration(UART2, &COMx_InitStructure);  // 初始化串口2 USART1,USART2,USART3,USART4

    BT_RS485_EN = 0;
}
/**
 * @brief  RS485 串口中断处理
 * @note
 * @retval
 */
void UART2_int(void) interrupt UART2_VECTOR
{
    if (RI2)
    {
        CLR_RI2();
        if (COM2.B_RX_OK == 0)
        {
            if (COM2.RX_Cnt >= COM_RX2_Lenth)
                COM2.RX_Cnt = 0;
            RX2_Buffer[COM2.RX_Cnt++] = S2BUF;
            if (COM2.RX_Cnt >= COM_RX2_Lenth)
                COM2.RX_Cnt = 0;
            COM2.RX_TimeOut = TimeOutSet2;
        }
    }

    if (TI2)
    {
        CLR_TI2();
        if (COM2.TX_read != COM2.TX_write)
        {
            BT_RS485_EN = 1;
            S2BUF = TX2_Buffer[COM2.TX_read];
            if (++COM2.TX_read >= COM_TX2_Lenth)
                COM2.TX_read = 0;
        }
        else
        {
            BT_RS485_EN = 0;
            COM2.B_TX_busy = 0;
        }
    }
}